import os
import sys
import subprocess
import time
import psutil
import webbrowser
from typing import Optional

# 项目根目录
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))

def check_port_used(port: int) -> bool:
    """
    检查端口是否被占用
    """
    for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
        try:
            for conns in proc.connections(kind='inet'):
                if conns.laddr.port == port:
                    return True
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            pass
    return False

def start_api_server(port: int = 8000, use_reload: bool = True) -> Optional[subprocess.Popen]:
    """
    启动API服务
    """
    if check_port_used(port):
        print(f"错误: 端口 {port} 已被占用，请先停止占用该端口的进程")
        return None
    
    print(f"正在启动API服务 (端口: {port})...")
    
    # 构建命令
    cmd = [
        sys.executable,
        os.path.join(PROJECT_ROOT, 'src', 'api', 'server.py'),
        '--port', str(port)
    ]
    
    if use_reload:
        cmd.append('--reload')
    
    # 启动进程
    try:
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            cwd=PROJECT_ROOT
        )
        
        # 等待服务启动
        print("等待服务启动中...")
        time.sleep(3)
        
        # 检查进程是否仍在运行
        if process.poll() is not None:
            # 进程已退出，打印错误信息
            stderr = process.stderr.read()
            print(f"服务启动失败:\n{stderr}")
            return None
        
        print(f"API服务已成功启动，监听端口: {port}")
        print(f"健康检查地址: http://localhost:{port}/health")
        print(f"API文档地址: http://localhost:{port}/docs")
        
        return process
    except Exception as e:
        print(f"启动服务时出错: {e}")
        return None

def train_all_models():
    """
    训练所有模型
    """
    print("开始训练所有模型...")
    
    models = [
        ('硬件预测模型', os.path.join('src', 'models', 'train_hardware_model.py')),
        ('软件异常检测模型', os.path.join('src', 'models', 'train_software_model.py')),
        ('工单分类模型', os.path.join('src', 'models', 'train_ticket_model.py'))
    ]
    
    for model_name, script_path in models:
        print(f"\n=== 训练 {model_name} ===")
        script_full_path = os.path.join(PROJECT_ROOT, script_path)
        
        if not os.path.exists(script_full_path):
            print(f"警告: 脚本不存在: {script_full_path}")
            continue
        
        try:
            subprocess.run(
                [sys.executable, script_full_path],
                check=True,
                cwd=PROJECT_ROOT
            )
            print(f"{model_name} 训练完成")
        except subprocess.CalledProcessError as e:
            print(f"{model_name} 训练失败: {e}")
        except Exception as e:
            print(f"训练 {model_name} 时出错: {e}")
    
    print("\n所有模型训练完成")

def check_dependencies():
    """
    检查依赖是否安装
    """
    print("检查项目依赖...")
    
    try:
        import lightgbm
        import pandas
        import numpy
        import scikit_learn
        import fastapi
        import uvicorn
        import shap
        import yaml
        
        print("所有必要的依赖都已安装")
        return True
    except ImportError as e:
        print(f"缺少依赖: {e.name}")
        print("请运行以下命令安装依赖:")
        print(f"pip install -r {os.path.join(PROJECT_ROOT, 'requirements.txt')}")
        return False

def open_browser_docs(port: int = 8000):
    """
    在浏览器中打开API文档
    """
    try:
        webbrowser.open(f"http://localhost:{port}/docs")
        print("已在浏览器中打开API文档")
    except Exception as e:
        print(f"无法打开浏览器: {e}")

def print_menu():
    """
    打印菜单
    """
    print("\n" + "=" * 50)
    print("物联网价签业务LightGBM服务 - 启动菜单")
    print("=" * 50)
    print("1. 启动API服务")
    print("2. 训练所有模型")
    print("3. 安装依赖")
    print("4. 查看项目结构")
    print("5. 退出")
    print("=" * 50)

def view_project_structure():
    """
    查看项目结构
    """
    print("\n项目结构:")
    
    try:
        if sys.platform.startswith('win'):
            subprocess.run(['dir', '/s', '/b'], shell=True, cwd=PROJECT_ROOT)
        else:
            subprocess.run(['find', '.', '-type', 'f'], cwd=PROJECT_ROOT)
    except Exception as e:
        print(f"无法显示项目结构: {e}")

def install_dependencies():
    """
    安装项目依赖
    """
    requirements_path = os.path.join(PROJECT_ROOT, 'requirements.txt')
    
    if not os.path.exists(requirements_path):
        print(f"错误: 找不到依赖文件: {requirements_path}")
        return
    
    print(f"正在安装项目依赖...")
    
    try:
        subprocess.run(
            [sys.executable, '-m', 'pip', 'install', '-r', requirements_path],
            check=True
        )
        print("依赖安装完成")
    except subprocess.CalledProcessError as e:
        print(f"依赖安装失败: {e}")
    except Exception as e:
        print(f"安装依赖时出错: {e}")

def main():
    """
    主函数
    """
    api_process = None
    
    while True:
        print_menu()
        choice = input("请选择操作 (1-5): ")
        
        if choice == '1':
            if api_process is not None:
                print("API服务已经在运行")
                continue
            
            if not check_dependencies():
                install_confirm = input("是否现在安装依赖? (y/n): ")
                if install_confirm.lower() == 'y':
                    install_dependencies()
                else:
                    continue
            
            port = input("请输入端口号 (默认: 8000): ")
            port = int(port) if port.isdigit() else 8000
            
            api_process = start_api_server(port=port)
            if api_process:
                open_confirm = input("是否在浏览器中打开API文档? (y/n): ")
                if open_confirm.lower() == 'y':
                    open_browser_docs(port=port)
        
        elif choice == '2':
            if not check_dependencies():
                install_confirm = input("是否现在安装依赖? (y/n): ")
                if install_confirm.lower() == 'y':
                    install_dependencies()
                else:
                    continue
            
            train_all_models()
        
        elif choice == '3':
            install_dependencies()
        
        elif choice == '4':
            view_project_structure()
        
        elif choice == '5':
            if api_process is not None:
                print("停止API服务...")
                api_process.terminate()
                api_process.wait(timeout=5)
            
            print("感谢使用！再见")
            break
        
        else:
            print("无效的选择，请重新输入")


if __name__ == "__main__":
    main()
